package fr.sedoo.commons.client.crud.widget;

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;

import com.google.gwt.cell.client.Cell;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.view.client.HasData;
import com.google.gwt.view.client.ListDataProvider;

import fr.sedoo.commons.client.message.CommonMessages;
import fr.sedoo.commons.client.widget.ConfirmCallBack;
import fr.sedoo.commons.client.widget.DialogBoxTools;
import fr.sedoo.commons.client.widget.dialog.EditDialogContent;
import fr.sedoo.commons.client.widget.dialog.OkCancelDialog;
import fr.sedoo.commons.client.widget.style.CellTableResources;
import fr.sedoo.commons.client.widget.table.FormattedCellTable;
import fr.sedoo.commons.client.widget.table.ImagedActionCell;
import fr.sedoo.commons.client.widget.table.TableBundle;
import fr.sedoo.commons.shared.domain.HasIdentifier;

public abstract class CrudTable extends Composite implements ClickHandler {

	protected List<? extends HasIdentifier> model;
	protected FormattedCellTable<HasIdentifier> table;

	protected VerticalPanel tablePanel;
	protected HorizontalPanel toolBarPanel;
	private Image addImage;
	protected Label addItemLabel;
	private Image deleteImage = new Image(TableBundle.INSTANCE.delete());
	private Image editImage = new Image(TableBundle.INSTANCE.edit());

	protected Column<HasIdentifier, String> deleteColumn;
	protected Column<HasIdentifier, String> editColumn;

	public abstract String getAddItemText();

	public abstract String getEditDialogTitle();

	public abstract EditDialogContent getEditDialogContent(
			EditConfirmCallBack callBack, HasIdentifier hasIdentifier);

	public abstract String getCreateDialogTitle();

	public abstract EditDialogContent getCreateDialogContent(
			CreateConfirmCallBack callBack, HasIdentifier hasIdentifier);

	public abstract HasIdentifier createNewItem();

	private ListDataProvider<HasIdentifier> dataProvider = new ListDataProvider<HasIdentifier>();

	private HorizontalPanel emptyListPanel;

	private boolean addButtonEnabled = false;

	private boolean askDeletionConfirmation = true;

	protected CrudPresenter presenter;

	public CrudTable() {
		super();

		if (tablePanel == null) {
			tablePanel = new VerticalPanel();
		} else {
			tablePanel.clear();
		}

		emptyListPanel = new HorizontalPanel();
		emptyListPanel.add(new Label(CommonMessages.INSTANCE.emptyList()));

		checkEmptyPanelVisibility();

		tablePanel.add(emptyListPanel);

		table = new FormattedCellTable<HasIdentifier>(Integer.MAX_VALUE,
				CellTableResources.INSTANCE);
		table.setWidth("100%", false);

		Cell<HasIdentifier> deleteActionCell = new ImagedActionCell<HasIdentifier>(
				deleteAction, this.deleteImage,
				CommonMessages.INSTANCE.delete());
		deleteColumn = new Column(deleteActionCell) {

			@Override
			public HasIdentifier getValue(Object object) {
				return (HasIdentifier) object;
			}
		};

		Cell<HasIdentifier> editActionCell = new ImagedActionCell<HasIdentifier>(
				editAction, this.editImage, CommonMessages.INSTANCE.edit());
		editColumn = new Column(editActionCell) {

			@Override
			public HasIdentifier getValue(Object object) {
				return (HasIdentifier) object;
			}
		};

		toolBarPanel = new HorizontalPanel();
		toolBarPanel.setSpacing(5);
		// addItemPanel.setWidth("100%");
		addImage = new Image(TableBundle.INSTANCE.add());
		addImage.setStyleName("clickableImage");
		toolBarPanel.add(addImage);
		addItemLabel = new Label(getAddItemText());
		addItemLabel.setStyleName("clickableImage");
		toolBarPanel.add(addItemLabel);
		tablePanel.add(table);
		tablePanel.add(toolBarPanel);
		tablePanel.setWidth("100%");
		addImage.addClickHandler(this);
		addItemLabel.addClickHandler(this);
		initColumns();
		initWidget(tablePanel);

	}

	private void checkEmptyPanelVisibility() {
		if ((this.model == null) || (this.model.size() == 0)) {
			emptyListPanel.setVisible(true);
			if (table != null) {
				table.setVisible(false);
			}
		} else {
			emptyListPanel.setVisible(false);
			if (table != null) {
				table.setVisible(true);
			}
		}

	}

	protected void initColumns() {
		table.addColumn(editColumn);
		table.addColumn(deleteColumn);
		table.setColumnWidth(editColumn, 30.0, Unit.PX);
		table.setColumnWidth(deleteColumn, 30.0, Unit.PX);
	}

	public List<? extends HasIdentifier> getModel() {
		return model;
	}

	public void setModel(List<? extends HasIdentifier> model) {
		this.model = model;
	}

	public void presenterDelete(HasIdentifier hasIdentifier) {
		presenter.delete(hasIdentifier);
	}

	public void init(List<? extends HasIdentifier> model) {
		setModel(model);
		checkEmptyPanelVisibility();
		// TODO : Tester si on la pas d�j� fait
		Set<HasData<HasIdentifier>> dataDisplays = dataProvider
				.getDataDisplays();
		if (dataDisplays.size() != 0) {
			dataProvider.removeDataDisplay(table);
		}
		dataProvider.addDataDisplay(table);
		List<HasIdentifier> list = dataProvider.getList();
		list.clear();
		list.addAll(this.model);
		table.setRowData(dataProvider.getList());
	}

	public void onClick(ClickEvent event) {
		if ((event.getSource() == addImage)
				|| (event.getSource() == addItemLabel)) {
			if (addButtonEnabled == true) {
				addItem();
			} else {
				DialogBoxTools.modalAlert("Not activated",
						"Not activated in this mode");
			}
		}
	}

	public String getDeleteItemConfirmationText() {
		return CommonMessages.INSTANCE.deletionConfirmMessage();
	}

	ImagedActionCell.Delegate<HasIdentifier> deleteAction = new ImagedActionCell.Delegate<HasIdentifier>() {

		@Override
		public void execute(final HasIdentifier hasIdentifier) {

			if (isAskDeletionConfirmation() == false) {
				presenterDelete(hasIdentifier);
			} else {
				ConfirmCallBack callBack = new ConfirmCallBack() {

					@Override
					public void confirm(boolean choice) {
						if (choice == true) {
							presenterDelete(hasIdentifier);
						}

					}
				};

				DialogBoxTools.modalConfirm(CommonMessages.INSTANCE.confirm(),
						getDeleteItemConfirmationText(), callBack).center();
			}
		}

	};

	ImagedActionCell.Delegate<HasIdentifier> editAction = new ImagedActionCell.Delegate<HasIdentifier>() {

		@Override
		public void execute(HasIdentifier hasCode) {
			presenterEdit(hasCode);

		}

	};

	public void removeRow(HasIdentifier deletedItem) {

		ListIterator<? extends HasIdentifier> listIterator = model
				.listIterator();
		while (listIterator.hasNext()) {
			HasIdentifier hasIdentifier = listIterator.next();
			if (hasIdentifier.getIdentifier().compareTo(
					deletedItem.getIdentifier()) == 0) {
				listIterator.remove();
				break;
			}
		}
		init(model);
	}

	public void addRow(HasIdentifier addedItem) {
		List<HasIdentifier> aux = new ArrayList<HasIdentifier>();
		ListIterator<? extends HasIdentifier> listIterator = model
				.listIterator();
		while (listIterator.hasNext()) {
			aux.add(listIterator.next());
		}
		aux.add(addedItem);
		init(aux);
	}

	public HasIdentifier getItemById(String identifier) {
		ListIterator<? extends HasIdentifier> listIterator = model
				.listIterator();
		while (listIterator.hasNext()) {
			HasIdentifier hasIdentifier = listIterator.next();
			if (hasIdentifier.getIdentifier().compareTo(identifier) == 0) {
				return hasIdentifier;
			}
		}
		return null;
	}

	public void setAddButtonEnabled(boolean activated) {
		this.addButtonEnabled = activated;
	}

	public boolean isAskDeletionConfirmation() {
		return askDeletionConfirmation;
	}

	public void setAskDeletionConfirmation(boolean askDeletionConfirmation) {
		this.askDeletionConfirmation = askDeletionConfirmation;
	}

	/*
	 * public Long getMaxId() { Long maxId = 0L; Iterator<? extends
	 * HasIdentifier> iterator = model.iterator(); while (iterator.hasNext()) {
	 * HasIdentifier aux = (HasId) iterator.next(); if (aux.getId()> maxId) {
	 * maxId = aux.getId(); } } return maxId; }
	 */

	public void presenterEdit(HasIdentifier hasIdentifier) {
		OkCancelDialog dialog = new OkCancelDialog(getEditDialogTitle(),
				getEditDialogContent(getEditConfirmCallBack(), hasIdentifier));
		dialog.show();
	}

	public void addItem() {
		OkCancelDialog dialog = new OkCancelDialog(getCreateDialogTitle(),
				getCreateDialogContent(getCreateConfirmCallBack(),
						createNewItem()));
		dialog.show();
	}

	private EditConfirmCallBack getEditConfirmCallBack() {
		return new EditConfirmCallBack(getPresenter());
	}

	private CreateConfirmCallBack getCreateConfirmCallBack() {
		return new CreateConfirmCallBack(getPresenter());
	}

	public CrudPresenter getPresenter() {
		return presenter;
	}

	public void setPresenter(CrudPresenter presenter) {
		this.presenter = presenter;
	}

	public void updateRow(HasIdentifier updatedItem) {
		boolean added = false;
		List<HasIdentifier> aux = new ArrayList<HasIdentifier>();
		ListIterator<? extends HasIdentifier> listIterator = model
				.listIterator();
		while (listIterator.hasNext()) {
			HasIdentifier current = listIterator.next();
			if (current.getIdentifier().compareToIgnoreCase(
					updatedItem.getIdentifier()) == 0) {
				aux.add(updatedItem);
				added = true;
			} else {
				aux.add(current);
			}
		}
		if (added == false) {
			aux.add(updatedItem);
		}
		init(aux);
	}

	public void hideToolBar() {
		toolBarPanel.setVisible(false);
	}

}
